#ifndef __ADDERS_H
#define __ADDERS_H

#include "register.h"

/*
 * Full adder structure
 */
typedef struct
{
	Bit a;
	Bit b;
	Bit carry_in;
	Bit result;
	Bit carry_out;
} FullAdder;

typedef FullAdder * FullAdderPtr;

/*
 * Initializes a new instance of a full adder.
 */
FullAdderPtr fullAdderConstruct(void);

/*
 * Sets the input bits for the adder.
 */
void fullAdderSetInputs(FullAdderPtr adder, Bit a, Bit b, Bit carry_in);

/*
 * Performs the addition operation. This method must be called before fullAdderGetResult or
 * fullAdderGetCarryOut.
 */
void fullAdderAdd(FullAdderPtr adder);

/*
 * Gets the result of the addition operation. The fullAdderAdd method must be called before this
 * method.
 */
Bit fullAdderGetResult(FullAdderPtr adder);

/*
 * Gets the carry-out bit of the the addition operation. The fullAdderAdd method must be called
 * before this method.
 */
Bit fullAdderGetCarryOut(FullAdderPtr adder);

/*
 * Frees an instance of a full adder.
 */
void fullAdderDestruct(FullAdderPtr adder);

typedef struct
{
	FullAdderPtr adders[REGISTER_BITS];
	Register a;
	Register b;
	Register result;
	unsigned char flags; // flags[0]=O, flags[1]=C, flags[2]=Z, flags[3]=N
} RippleCarryAdder;

typedef RippleCarryAdder * RippleCarryAdderPtr;

/*
 * Initializes a new instance of a ripple carry adder.
 */
RippleCarryAdderPtr rippleCarryAdderConstruct(void);

/*
 * Sets the input registers for the adder.
 */
void rippleCarryAdderSetRegisters(RippleCarryAdderPtr adder, Register a, Register b);

/*
 * Performs the addition operation. This method must be called before rippleCarryAdderGetResult or
 * rippleCarryAdderGetFlags.
 */
void rippleCarryAdderAdd(RippleCarryAdderPtr adder);

/*
 * Gets the register result of the addition operation. The rippleCarryAdderAdd method must be
 * called before this method.
 */
Register rippleCarryAdderGetResult(RippleCarryAdderPtr adder);

/*
 * Gets the flags from the addition operation. The rippleCarryAdderAdd method must be called before
 * this method.
 */
unsigned char rippleCarryAdderGetFlags(RippleCarryAdderPtr adder);

/*
 * Frees an instance of a ripple carry adder.
 */
void rippleCarryAdderDestruct(RippleCarryAdderPtr adder);

#endif
